import json
import glob
import os
from datetime import datetime

import numpy as np
import pandas as pd
from nltk.tokenize import word_tokenize

from feature_set.sms.utils.data_utils import ngrams
from feature_set.base_feature import BaseFeature, RequstData
from collections import Counter
from feature_conf.config.constant import *
from feature_set.sms.utils.sender_word_utils.sms_utils import time_trans
import sys

sys.path.append("../../")


class AppUnWoeV1(BaseFeature):
    def __init__(self, conf_path):
        super().__init__()
        self.order_split_file_name = 'order_split_no.conf'
        self.app_woe_level_file_name = 'app_woe_level.conf'
        self.conf_path = conf_path
        self.load_conf()

        self.user_apps = None
        self.random_no = None
        self.woe_level_list = None

        self.time_windows = ['1d', '3d', '7d', '15d', '30d', '60d', '120d', '180d', 'all']

        self.function_map = {
            'time_window': self.time_statis_features
        }

    def load_conf(self):
        self.conf = {}
        path_list = os.path.abspath(__file__).split(os.sep)
        featurelib_index = path_list.index('featurelib')
        featurelib_path = os.sep.join(path_list[0:featurelib_index + 1])
        conf_path = os.sep.join([featurelib_path, 'feature_conf', self.conf_path])

        order_split_file = os.path.join(conf_path, self.order_split_file_name)
        self.conf['order_split'] = pd.read_parquet(order_split_file)

        app_woe_levels = os.path.join(conf_path, self.app_woe_level_file_name)
        app_woe_levels = pd.read_parquet(app_woe_levels)

        app_woe_levels['woe_level'] = app_woe_levels['woe_level'].map(lambda x: str(int(x)))
        app_woe_levels['level_tag'] = np.where(app_woe_levels['lift'] > 1, 'higth_lift', 'low_lift')

        self.conf['app_woe_levels'] = {}

        random_nos = app_woe_levels['random_no'].unique()
        self.woe_level_list = app_woe_levels['woe_level'].nunique()

        for random_no in random_nos:
            self.conf['app_woe_levels'][random_no] = app_woe_levels[(app_woe_levels['random_no'] == random_no)]

    def load_request(self, request_data: RequstData):
        """
        加载数据到对象
        """
        # tx_id = request_data.tx_id
        # app_user_id = request_data.app_user_id
        order_id = request_data.order_id
        country_id = request_data.country_abbr
        apply_time = request_data.apply_time

        order_split = self.conf['order_split']
        order_split = order_split[order_split['app_order_id'] == str(order_id)]['random_no'].to_list()
        if len(order_split) > 0:
            random_no = str(order_split[0])
        else:
            random_no = 'all'
        self.random_no = random_no

        assert country_id in GenericConfigConstant.COUNTRY_ID, "country id not in list, Please input correct country id"

        app_list = []
        try:
            applist_data = request_data.data_sources["applist_data"]
            app_list = (
                json.loads(applist_data) if type(applist_data) == str else applist_data
            )
        except:
            pass

        if len(app_list) == 0:
            user_apps = pd.DataFrame(app_list,
                                     columns=['app_name', 'app_package', 'app_version', 'device_id', 'fi_time',
                                              'isSystem', 'lu_time'])
        else:
            user_apps = pd.DataFrame(app_list)

        user_apps['package_id'] = user_apps['app_package']
        user_apps.loc[:, 'fi_time'] = user_apps['fi_time'].apply(lambda x: time_trans(x, country_id))
        user_apps['fi_time'] = np.where(user_apps['fi_time'] > '2050-12-01' , pd.to_datetime(0),user_apps['fi_time'])
        user_apps['fi_time'] = pd.to_datetime(user_apps['fi_time'])
        user_apps['apply_time'] = pd.Timestamp(apply_time)
        user_apps = user_apps[user_apps['fi_time'] < user_apps['apply_time']]
        user_apps['apply_day'] = user_apps['apply_time'].dt.normalize()
        user_apps['fi_day'] = user_apps['fi_time'].dt.normalize()
        user_apps['date_diff'] = (user_apps['apply_day'] - user_apps['fi_day']).dt.days

        user_apps = user_apps.merge(self.conf['app_woe_levels'][random_no], on = 'package_id', how='left')

        for time_wind in self.time_windows:
            if time_wind == 'all':
                user_apps[time_wind] = 1
            else:
                days = int(time_wind.replace('d', ''))
                user_apps[time_wind] = np.where(user_apps['date_diff'] <= days, 1, 0)
        self.user_apps = user_apps

    def time_grouped_feature(self, groupby):
        result = {}
        random_no = self.random_no
        user_apps = self.user_apps

        app_woe_levels_df = self.conf['app_woe_levels'][random_no]

        totol_app_count = user_apps['app_package'].nunique()

        level_conf_grouped = app_woe_levels_df.groupby(groupby).agg(
            level_app_unique=('package_id', 'nunique'))

        for time_wind in self.time_windows:
            app_grouped = user_apps[user_apps[time_wind] == 1].groupby(groupby).agg(
                app_nunique=('package_id', 'nunique')
            )

            result_df = pd.concat([level_conf_grouped, app_grouped], axis=1)
            result_df['app_rate']  = result_df['app_nunique'] / totol_app_count
            result_df['level_app_rate'] = result_df['app_nunique'] / result_df['level_app_unique']
            result_df = result_df.fillna(0)
            for i ,row in result_df.iterrows():
                for col in ['app_nunique','app_rate','level_app_rate']:
                    feature_name = f'{groupby}_{i}_{col}_{time_wind}'
                    result[feature_name] = row[col]
        return result

    def time_statis_features(self):
        result = self.time_grouped_feature('level_tag')
        result1 =  self.time_grouped_feature('woe_level')
        result.update(result1)
        return result
